"""
    This file is part of django-simp.

    django-simp is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    django-simp is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with django-simp.  If not, see <http://www.gnu.org/licenses/>.
"""

import os.path, shutil, os
from django.db import models
from django.utils import simplejson
from django.contrib import admin
from PIL import Image

from simp.settings import *

import uuid

class ModuleManager(models.Manager):
	loadedModules = {}
	
	def all_pymods(self):
		pymods = []
		mods = self.all()
		for mod in mods:
			pymods.append(mod.get_pymod())
		return pymods
		
	
	def get_pymod(self, moduleName):
		return self.get(pk=moduleName).get_pymod()
	
	def get_scripts(self, module, ctrl):
		mod = self.get(pk=module).get_pymod()
		return mod.get_script(ctrl)
	
	def get_toolbars(self, module, ctrl):
		mod = self.get(pk=module).get_pymod()
		return mod.get_toolbar(ctrl)
	
	def get_editor(self, module, ctrl):
		mod = self.get(pk=module).get_pymod()
		return mod.get_editor(ctrl)
	
	def get_default_preset(self, ctrl):
		modpreset = Preset.objects.get_modpreset(module=self.get(default=True), preset_order=0);
		return modpreset
	
	def get_default_editor(self, ctrl):
		mod = self.get(default=True).get_pymod()
		return mod.get_editor(ctrl)


class Module(models.Model):
	name = models.CharField(max_length=64, primary_key=True)
	module = models.CharField(max_length=256)
	default = models.BooleanField()
	
	objects = ModuleManager()
	
	def __unicode__(self):
		return self.name + ": " + self.module
	def __str__(self):
		return self.name + ": " + self.module
	
	def get_pymod(self):
		modpath = self.module
		if modpath.startswith('.'):
			modpath = "simp%s" % modpath
		m = __import__(modpath, {}, {}, [''])
		return m
		
	class Admin:
		pass
	
	class Meta:
		ordering = ['name']

class ModuleOptions(admin.ModelAdmin):	
    list_display = ('name', 'module', 'default')       

admin.site.register(Module, ModuleOptions);

class PresetManager(models.Manager):
	def get_modpreset(self, module, preset_order):
		return self.get(module=module, order=preset_order).get_modpreset()

class Preset(models.Model):
	module = models.ForeignKey(Module, related_name="presets")
	label = models.CharField(max_length=320)
	values = models.CharField(max_length=512)
	order = models.IntegerField()
	#needs_perms = models.CharField(max_length=320)
	
	objects = PresetManager()
	
	def __unicode__(self):
		return str(self.module) + ":" + str(self.order)
	def __str__(self):
		return str(self.module) + ":" + str(self.order)
	
	def get_modpreset(self):
		modpreset = self.module.get_pymod().ModPreset(self)
		return modpreset
	
	class Admin:
		pass
	
	class Meta:
		ordering = ['module', 'order']

class PresetOptions(admin.ModelAdmin):    
    list_display = ('module', 'label', 'order', 'values')       

admin.site.register(Preset, PresetOptions);
		
class ModulePresetBase:
	model = None
	_dict_ignore = ['__init__', 'from_json', 'from_dict', 'to_dict', 'to_json', 'save_to_model', 'model', '_dict_ignore', '__doc__', '__module__']
	
	def __init__(self, model):
		self.model = model
		self.from_json(self.model.values)
		

	def from_json(self, json):
		dict = simplejson.loads(json)
		self.from_dict(dict)
		
	def from_dict(self, dict):
		for key, value in dict.items():
			if not key in self._dict_ignore:
				self.__dict__[key] = value

	def to_dict(self):
		values = {}
		for key in dir(self.__class__):
			if not key in self._dict_ignore:
				values[key] = getattr(self, key)
		return values   
	
	def to_json(self):
		dict = self.to_dict()
		return simplejson.dumps(dict) 
	
	def save_to_model(self):
		self.model.values = self.to_json()
		self.model.save()
	
class InstanceManager(models.Manager):
	def get_by_request(self, request):
		inst = None
		if request.session.get('simp_instance', False):
			inst = self.get(pk=request.session['simp_instance'])
		else:
			inst = self.get(session=request.COOKIES[settings.SESSION_COOKIE_NAME])
		return inst

	def create_for_request(self, request):
		pass

	
class Instance(models.Model):
	id = models.CharField(primary_key=True, max_length=64)
	session = models.CharField(max_length=320)
	embedded = models.BooleanField()
	image = models.ImageField(upload_to="./")	
	preset = models.ForeignKey(Preset, null=True, blank=True)
	callback = models.CharField(max_length=256)
	save_as = models.CharField(max_length=256)
	
	objects = InstanceManager()
	
	def __unicode__(self):
		return "SimpInstance: %s" % str(self.id)
	
	def __str__(self):
		return "SimpInstance: %s" % str(self.id)
	
	def get_image(self):
		inst_path = os.path.join(SIMP_DATAPATH, str(self.id))
		image = None
		if os.path.exists(inst_path):
			try:
				image = ImageFile.objects.get(next=None, instance=self)
			except models.ObjectDoesNotExist:
				image = self.create_image()
		else:
			image = self.create_image()
		return image

	def create_image(self):
		inst_path = os.path.join(SIMP_DATAPATH, str(self.id))
		if os.path.exists(inst_path) == False:
			os.mkdir(inst_path)
		filename = str(uuid.uuid4()) + ".jpg"
		shutil.copy(self.get_image_filename(), os.path.join(inst_path, filename)),
		image = ImageFile()
		image.image = os.path.join(SIMP_POSTFIX, str(self.id), filename)
		image.instance = self
		image.preset = None
		image.module = None
		image.desc = "init imageFile"
		image.save()
		return image		
	
	def get_last_commit(self):
		pass
	
	def get_next_image(self):
		pass
	
	def get_preset(self, module, order):
		pass

	def deleteWholeInstance(self):
		imageFiles = ImageFile.objects.filter(instance=self)
		imageFiles = imageFiles.order_by('time')
		for imageFile in imageFiles:
			imageFile.deleteWithFile()
		os.rmdir(os.path.join(SIMP_DATAPATH, str(self.id)))
		
class InstanceOptions(admin.ModelAdmin):    
    list_display = ('id', 'session', 'image', 'preset')       

admin.site.register(Instance, InstanceOptions);
	
class ImageFileManager(models.Manager):
	def get_latest_commit(self, instance):
		pass
	
	def get_first_commit(self, instance):
		pass
		
	
class ImageFile(models.Model):
	instance = models.ForeignKey(Instance)
	desc = models.CharField(max_length=256)
	module = models.ForeignKey(Module, null=True)
	preset = models.ForeignKey(Preset, blank=True, null=True) 
	values = models.CharField(max_length=256) 
	image = models.ImageField(upload_to="simp/", null=True)
	next = models.ForeignKey('self', related_name="previous", blank=True, null=True)
	commit = models.BooleanField()
	time = models.DateField(auto_now=True)
	
	objects = ImageFileManager()
	
	def __unicode__(self):
		return "%s:%s:%s" % (self.instance, self.desc, self.time)
	
	def __str__(self):
		return "%s:%s:%s" % (self.instance, self.desc, self.time)
	
	def get_image_dict(self):
		dict = {}
		dict["url"] = self.get_image_url()
		dict["height"] = self.get_image_height()
		dict["width"] = self.get_image_width()
		return dict
	
	def create_next(self):
		if (self.image != None):
			filename = SIMP_POSTFIX + str(self.instance.id) + "/" + str(uuid.uuid4()) + ".jpg"
			nextImg = ImageFile(instance=self.instance, image=filename)
			#nextImg.save()
			self.next = nextImg
			return nextImg
		return None
	
	def get_next(self):
		if (self.next == None):
			nextImg = self.create_next()
			self.next = nextImg
		return self.next
	
	def apply_next(self, nextImg):
		if nextImg != None:
			nextImg.save()
			self.next = nextImg;
			self.save()
			return nextImg
		else:
			raise "unable to apply None as next imagefile"
		
	def deleteWithFile(self):
		os.remove(self.get_image_filename())
		self.delete()

	class Meta:
		ordering = ['instance', 'time']

class ImageFileOptions(admin.ModelAdmin):    
    list_display = ('instance', 'desc', 'time', 'module', 'preset')       

admin.site.register(ImageFile, ImageFileOptions);

